Expand description

C ABI compatible string types

While rust’s stdlib has some good basic options for C-string support, it has some glaring issues when dealing with C functions that accept or return arrays of structures containing C-string pointers or arrays. This crate aims to help fill that niche with safe, fast, ergonomic alternatives.

C typeABI compatible Rustnull
const char *abistr::CStrPtr""
const char *Option<abistr::CStrNonNull>None
const char * __attribute__((nonnull))abistr::CStrNonNull❌ undefined ❌
char struct_member[128];abistr::CStrBuf<u8, 128>N/A
C++20ABI compatible Rust
const char8_t *abistr::CStrPtr<u8 >""
const char16_t *abistr::CStrPtr<u16>""
const char32_t *abistr::CStrPtr<u32>""
const char8_t *Option<abistr::CStrNonNull<u8 >>None
const char16_t *Option<abistr::CStrNonNull<u16>>None
const char32_t *Option<abistr::CStrNonNull<u32>>None
const char8_t * __attribute__((nonnull))abistr::CStrNonNull<u8 >❌ undefined ❌
const char16_t * __attribute__((nonnull))abistr::CStrNonNull<u16>❌ undefined ❌
const char32_t * __attribute__((nonnull))abistr::CStrNonNull<u32>❌ undefined ❌
char8_t struct_member[128];abistr::CStrBuf<u8, 128>N/A
char16_t struct_member[128];abistr::CStrBuf<u16, 128>N/A
char32_t struct_member[128];abistr::CStrBuf<u32, 128>N/A
iOS, OS XABI compatible Rust
const unichar *abistr::CStrPtr<u16>""
const wchar_t *abistr::CStrPtr<u32>""
const unichar *Option<abistr::CStrPtr<u16>>None
const wchar_t *Option<abistr::CStrPtr<u32>>None
const unichar * __attribute__((nonnull))abistr::CStrNonNull<u16>❌ undefined ❌
const wchar_t * __attribute__((nonnull))abistr::CStrNonNull<u32>❌ undefined ❌
unichar struct_member[128];abistr::CStrBuf<u16, 128>N/A
wchar_t struct_member[128];abistr::CStrBuf<u32, 128>N/A
LinuxABI compatible Rust
const wchar_t *abistr::CStrPtr<u32>""
const wchar_t *Option<abistr::CStrPtr<u32>>None
const wchar_t * __attribute__((nonnull))abistr::CStrNonNull<u32>❌ undefined ❌
wchar_t struct_member[128];abistr::CStrBuf<u32, 128>N/A
WindowsABI compatible Rust
const wchar_t *abistr::CStrPtr<u16>""
const wchar_t *Option<abistr::CStrPtr<u16>>None
const wchar_t * __attribute__((nonnull))abistr::CStrNonNull<u16>❌ undefined ❌
wchar_t struct_member[128];abistr::CStrBuf<u16, 128>N/A

Alternatives

*const c_char

  • Pro: Can’t get any simpler for basic interop!
  • Con: Requires unsafe to so much as shake a stick at.
  • Con: Easy to create undefined behavior by messing up edge cases involving null.
  • Con: Easy to create undefined behavior by creating dangling pointers and other lifetime issues (raw pointers have no lifetimes.)
  • Con: Fairly unergonomic to use directly.

&std::ffi::CStr

  • Pro: Relatively safe!
  • Con: Immediate O(n) length check on construction, even if you never use the string.
  • Con: Being a DST (at least at the time of writing / rust 1.48.0), this isn’t ABI compatible with *const c_char and thus cannot be embedded in zero-conversion structures.

std::ffi::CString - per &std::ffi::CStr, but also:

  • Pro: Dynamically allocated!
  • Con: Dynamically allocated.

Macros

Create a &CStrNonNull literal at compile time

Create a &CStrNonNull<u8> literal at compile time

Create a &CStrNonNull<u16> literal at compile time

Create a &CStrNonNull<u32> literal at compile time

Structs

The buffer in question is too small to contain the string in question

CStrBuf<Unit; 128> is ABI compatible with [Unit; 128].

Option<CStrNonNull<Unit>> is ABI compatible with *const Unit.

CStrPtr<Unit> is ABI compatible with *const Unit. null() is treated as an empty string.

The string in question contains no terminal \0, or contains an interior \0.

The string in question contains an interior \0.

The string in question contains no terminal \0

Traits

Treat self as a C-style string

Treat self as a C-style string or null()

Converts self (str/String/CStr/CString) into something that implements AsCStr

Converts self (str/String/CStr/CString/()) into something that implements AsOptCStr

u8/u16/u32, a rough analog to a Unicode Code Unit.